/**
 * 触控类
 */
define(function(require, exports, module) {

	// 是否可以支持 触控 事件
	var canTouch = ("createTouch" in document) || ('ontouchstart' in window);

	var beforDragEvent = canTouch ? "ontouchstart" : "onmousedown";
	var onDragingEvent = canTouch ? "ontouchmove"  : "onmousemove";
	var afterDragEvent = canTouch ? "ontouchend"   : "onmouseup";

	module.exports = Touch;

	/**
	 * 是否支持触控
	 * @return {Boolean} [description]
	 */
	module.exports.isSupprtTouch = function(){
		return canTouch;
	}

    module.exports.getAngle = getAngle;
    module.exports.getDirectionFromAngle = getDirectionFromAngle;

	/**
	 * 构造函数
	 * @param {[type]} cfg [description]
	 */
	function Touch(cfg){


		this.on('beforeMove', function(){
			// console.log('开始拖动');
		});
		this.on('moving', function(){
			// console.log('开始拖动');
		});
		this.on('afterMove', function(){
			// console.log('开始拖动');
		});

		this.cfg.moverEl[beforDragEvent] = initMove.bind(this);
		
		if(window.navigator.isAndroid_4){
			this.touchendTimerId;
		}
	}

	/**
	 * 初始化 touch 事件，清空上次记录（direction、distance），并记录第一击的事件信息。
	 * 绑定 move、end 事件。
	 * @param  {EventObject} e [description]
	 * @return {[type]}   [description]
	 */
	function initMove(e){
		e = e || window.event; // if that is W3C Event Object, take the first one.

		// 上次移动的参数
		this.lastData = {
			direction : null,
			distance  : null,
			/*
			 * clientX和clientY表示的位置是相对浏览器窗口的，而不是对文档的，
			 * 因此当你在滚动页面之后仍然在窗口中的同一位置上单击时，所得到的坐标的值是相同的。
			 */
			x 		  : canTouch ? e.touches.item(0).pageX : e.clientX,
			y         : canTouch ? e.touches.item(0).pageY : e.clientY
		};

		var cfg = this.cfg;

		// 每次拖动都会分别登记一次 onmousemove 事件和 onmouseup 事件。
		// 拖动完，又会自动撤销上述事件的。
		// 登记到 onmousedown 事件中，不撤销，而 onmousemove / onmouseup 则会撤销
		cfg.moverEl[onDragingEvent] = moving.bind(this);	// 拖动时都会触发该事件
		cfg.moverEl[afterDragEvent] = afterMove.bind(this); // 松开按键时，要撤销 onmousemove 和 onmouseup 事件。

		this.fire('beforeMove', e);

		// 这里控制是否控制上报事件，
		// return false; // android 这里允许 事件上报的话很慢
	}

	/**
	 * 记录 touch 信息，信息包括坐标、角度、方向、距离。
	 * 把这些信息记录在 this.lastData 对象中。
	 * @param  {EventObject} e [description]
	 * @return {Array}   [description]
	 */
	function moving(e){
		e = e || window.event;

		var lastData = this.lastData;

		// 当前坐标 注意相反的
		var coordinate = {
			x : canTouch ? e.touches.item(0).pageX : e.clientX,
			y : canTouch ? e.touches.item(0).pageY : e.clientY
		};

		var lastXY = {
			x : lastData.x,
			y : lastData.y
		};

		// 角度:number
		var angle = getAngle(coordinate, lastXY);
		// 方向:string
		var direction = getDirectionFromAngle(angle);
		// 距离:number
		var disX = Math.abs(coordinate.x - lastData.x), disY = Math.abs(coordinate.y - lastData.y);

		var args = [e, direction, coordinate.x, lastData.x, disX, coordinate.y, disY]; // 供 after(fn) 调用的参数列表 

		fixTouchEndNotFire.apply(this, args);

		this.fire('moving', args);

		// 记录参数，放在最后
		this.lastData.direction = direction;
		this.lastData.disX = disX;
		this.lastData.disY = disY;
		this.lastData.x = coordinate.x;
		this.lastData.y = coordinate.y;
		
		return args;
	}

	/**
	 * 获取 move 事件最后一次的信息，送入到用户提供的事件处理器中。
	 * @param  {EventObject} e [description]
	 * @return {Array}   [description]
	 */
	function afterMove(e){
		e = e || window.event;
		var lastData = this.lastData;
		// 当前坐标就是上次的坐标、最后一次的坐标。
		this.fire('afterMove', [e, lastData.direction, lastData.x, lastData.disX, lastData.y, lastData.disY]);
		cleanMove.call(this, e);
	}

	/**
	 * 撤销 moving、moveend 事件
	 * @param  {EventObject} e [description]
	 * @return {[type]}   [description]
	 */
	function cleanMove(e){
		var moverEl = this.cfg.moverEl;
		moverEl[onDragingEvent] = moverEl[afterDragEvent] = null;
		// console.log('clean move finished!');
	}

    /**
     * 计算两点之间的角度。
     * calculate the angle between two points
     * @param  {Object}  pos1 { x: int, y: int }
     * @param  {Object}  pos2 { x: int, y: int }
     * @return {Number}
     */
	function getAngle(pos1, pos2){
        return Math.atan2(pos2.y - pos1.y, pos2.x - pos1.x) * 180 / Math.PI;
    }

    /**
     * 根据角度计算出方向。
     * angle to direction define
     * @param  {float}    angle
     * @return {string}   direction
     */
	function getDirectionFromAngle(angle){
        var directions = {
            down: angle >= 45 && angle < 135, //90
            left: angle >= 135 || angle <= -135, //180
            up: angle < -45 && angle > -135, //270
            right: angle >= -45 && angle <= 45 //0
        };
        var direction, key;
        for(key in directions){
            if(directions[key] === true){
                direction = key;
                break;
            }
        }
        return direction;
    }

    function fixTouchEndNotFire(e, direction, disX, disY){
    	/*
@bug touchend事件丢失，
或者到touchmove事件之后就终止掉。这是一个非常严重的bug。
使用touch事件时，在android 4.0 上面的浏览器手指在a元素上做滑动操作，然后手指离开，
结果不会触发 touchend事件，同样的操作在 android 2.x / ios上会触发 touchend。
解决办法：1、e.preventDefault(); 
2、兼容的解决办法是在 touchmove 时判断手势趋势大于预设值时（大于预设值证明有 move的动作趋势），停止默认的操作e.preventDefault()
http://www.mansonchor.com/blog/blog_detail_68.html
http://code.google.com/p/android/issues/detail?id=4549
http://www.uedspace.com/blog/576.html
*/
    	if(window.navigator.isAndroid_4){
			// window.clearTimeout(this.touchendTimerId);
			e.preventDefault();
			// alert(99999999996);
			// this.touchendTimerId = window.setTimeout(function(){
			// 	cleanMove.call(this);
			// 	this.afterDrag && obj.afterDrag(e, direction, disX, disY);
			// }, 20);
		} 	
    }
});